#!/usr/bin/perl

######################################################################
#
#  csv2tbl.pl
#
#     $Id: csv2tbl.pl 193 2014-03-10 03:34:49Z drj826@gmail.com $
#
#---------------------------------------------------------------------
# USAGE (execution)
#
#     perl csv2tbl.pl -c 1,3,4,6 -s 1 -- data.csv
#
#         --columns | -c => comma separated list of columns to include
#         --order   | -o => order by values in specified column
#         --skip    | -s => comma separated list of lines to skip
#         --shade        => shade odd rows with grey background
#         --number       => number rows
#
#---------------------------------------------------------------------
# USAGE (in SML document)
#
#     ---table
#     title: My Table
#     label: tab-my-table
#
#     :: Column 1 Header
#     :: Column 2 Header
#     :: Column 3 Header
#     :: Column 4 Header
#
#     ---
#
#     script: perl csv2tbl.pl -c 1,3,4,6 -s 1 -- data.csv
#
#     ---table
#
#---------------------------------------------------------------------
# DESCRIPTION
#
#     This script produces SML table rows from a CSV file. You can
#     specify which columns you wish to extract from the CSV file.  If
#     you don't specify the columns, the script will use all columns.
#
######################################################################

use strict;
use Text::CSV;
use Getopt::Long qw(:config no_ignore_case);

my @columns;                            # columns passed via argument
my @skip;                               # lines to skip
my $order;                              # order by this column
my $shade;                              # shade odd row backgrounds
my $number;                             # show row numbers

GetOptions
  (
   "columns|c=s" => \@columns,
   "order|o=s"   => \$order,
   "skip|s=s"    => \@skip,
   "shade|g!"    => \$shade,
   "number|g!"   => \$number,
  );

@columns = split(',',join(',',@columns));
@skip    = split(',',join(',',@skip));

my %skip_line;                          # lines to skip
foreach my $line (@skip) {
  $skip_line{$line} = 1;
}

my $file = shift;                       # CSV file to parse
my $data = read_csv_file($file);

my @sorted;

if ( $order )
  {
    @sorted = sort by_order @{ $data };
  }

else
  {
    @sorted = @{ $data };
  }

my $row = 0;
my $ord = 'even';

foreach my $record ( @sorted )
  {
    ++ $row;

    print "---\n\n" if $row != 1;

    if ( $ord eq 'odd' )
      {
	$ord = 'even';
      }

    else
      {
	$ord = 'odd';
      }

    if ( @columns )
      {
	if ($number)
	  {
	    if ( $shade and $ord eq 'odd' )
	      {
		print ":litegrey: $row\n\n";
	      }

	    else
	      {
		print ": $row\n\n";
	      }
	  }

	foreach my $column ( @columns )
	  {
	    my $value = $record->[$column - 1];

	    if ( $shade and $ord eq 'odd' )
	      {
		print ":litegrey: $value\n\n";
	      }

	    else
	      {
		print ": $value\n\n";
	      }
	  }
      }

    else
      {
	if ($number)
	  {
	    if ( $shade and $ord eq 'odd' )
	      {
		print ":litegrey: $row\n\n";
	      }

	    else
	      {
		print ": $row\n\n";
	      }
	  }

	foreach my $field (@{ $record })
	  {
	    if ( $shade and $ord eq 'odd' )
	      {
		print ":litegrey: $field\n\n";
	      }

	    else
	      {
		print ": $field\n\n";
	      }
	  }
      }
  }

######################################################################

sub read_csv_file {

  my $file = shift;

  my $data = [];
  my $line = 0;

  open my $fh, "< :encoding(UTF-8)", $file or die "$file not readable";

  while (<$fh>) {

    next if /^#/;                       # skip comment lines
    next if /^\s*$/;                    # skip blank lines

    ++ $line;

    next if $skip_line{$line};          # skip specified lines

    my $csv    = Text::CSV->new();
    my $status = $csv->parse($_);
    my $record = [ $csv->fields() ];

    push( @{$data}, $record );
  }

  close $fh;

  return $data;
}

######################################################################

sub by_order {
  lc($a->[$order - 1]) cmp lc($b->[$order - 1]);
}

######################################################################

1;
